#include "tasktimedialog.h"
#include "base/task/task.h"
#include "msgutils.h"
#include <QApplication>
#include <QLabel>
#include <QMessageBox>
#include <QProgressBar>
#include <QtDebug>
#include <QTimer>
#include <QVBoxLayout>

namespace yc {

TaskTimeDialog::TaskTimeDialog(yc::Task* task, const QString& error_msg, QWidget* parent)
    : QDialog(parent, Qt::MSWindowsFixedSizeDialogHint), error_msg_(error_msg), task_(task)
{
    progress_bar_ = new QProgressBar(this);
    progress_bar_->setObjectName("progress");
    progress_bar_->setTextVisible(false);
    progress_bar_->setRange(0, 1000);
    progress_bar_->setValue(0);

    left_label_ = new QLabel;
    left_label_->setObjectName("left");
    left_label_->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    updateLeftTime(task->evaluateTotalMSecs());

    QVBoxLayout* vl = new QVBoxLayout(this);
    vl->setContentsMargins(0, 0, 0, 0);
    vl->setSpacing(8);
    vl->addStretch();
    vl->addWidget(progress_bar_);
    vl->addWidget(left_label_);
    vl->addStretch();

    timer_ = new QTimer(this);
    connect(timer_, &QTimer::timeout, this, &TaskTimeDialog::onProgressTimer);
    timer_->start(500);

    // 修改task为子对象
    task->setParent(this);

    // signals
    connect(task, &yc::Task::finished, this, &TaskTimeDialog::close);
    connect(task, &yc::Task::failed, this, &TaskTimeDialog::onFailed);

    connect(progress_bar_, &QProgressBar::valueChanged, this,
            [this](int value) { updateLeftTime(progress_bar_->maximum() - value); });
}

TaskTimeDialog::~TaskTimeDialog()
{
    if (task_) {
        disconnect(task_, nullptr, this, nullptr);
        task_->terminate();
        task_->deleteLater();
    }
}

void TaskTimeDialog::closeEvent(QCloseEvent* ce)
{
    timer_->stop();
    if (task_) {
        disconnect(task_, nullptr, this, nullptr);
        task_->terminate();
        task_->deleteLater();
        task_ = nullptr;
    }
    QDialog::closeEvent(ce);
}

void TaskTimeDialog::updateLeftTime(qint64 msecs)
{
    int m = int(msecs / (60 * 1000));
    int s = int((msecs - m * 60000) / 1000);
    if (m > 0) {
        left_label_->setText(tr("Left: %1M%2S").arg(m).arg(s));
    } else {
        left_label_->setText(tr("Left: %1S").arg(s));
    }
}

void TaskTimeDialog::onProgressTimer()
{
    if (task_) {
        qint64 total_msecs = task_->evaluateTotalMSecs();
        qint64 elapsed = task_->elapsedMSecs();
        if (elapsed <= total_msecs) {
            qint64 min_elapsed = qint64(total_msecs * percent());
            progress_bar_->setMaximum(int(total_msecs));
            progress_bar_->setValue(int(qMax(elapsed, min_elapsed)));
        }
    }
}

qreal TaskTimeDialog::percent() const
{
    int maximum = progress_bar_->maximum();
    int value = progress_bar_->value();
    return (maximum <= 0 ? 0.0 : qMin(qreal(1.0), (qreal(value) / qreal(maximum))));
}

void TaskTimeDialog::onFailed(int error, const QString& message)
{
    Q_UNUSED(error)
    Q_UNUSED(message)
    disconnect(task_, nullptr, this, nullptr);
    timer_->stop();
    // show error message later
    const QString title = windowTitle();
    const QString msg = error_msg_;
    QTimer::singleShot(1, qApp, [title, msg] {
        msgutils::msgBox(QApplication::activeWindow(), title, msg, QMessageBox::Ok,
                         QMessageBox::NoButton, QMessageBox::Warning);
    });
    close();
}
} // namespace yc
